/* SPDX-License-Identifier: GPL-2.0 */
/* Copyright(c) 2021 Huawei Technologies Co., Ltd */

#ifndef HINIC3_COMMON_H
#define HINIC3_COMMON_H

#include <linux/types.h>

/**
 * struct hinic3_dma_addr_align - 对齐的 DMA 缓冲描述
 * @real_size: 真实申请大小
 * @ori_vaddr/ori_paddr: 原始(未对齐)的虚/物理地址
 * @align_vaddr/align_paddr: 确保按硬件要求对齐后的虚/物理地址
 */
struct hinic3_dma_addr_align {
	u32 real_size;

	void *ori_vaddr;
	dma_addr_t ori_paddr;

	void *align_vaddr;
	dma_addr_t align_paddr;
};

/**
 * enum hinic3_wait_return - 轮询等待的返回值
 * @WAIT_PROCESS_CPL: 已完成
 * @WAIT_PROCESS_WAITING: 继续等待
 * @WAIT_PROCESS_ERR: 错误退出
 */
enum hinic3_wait_return {
	WAIT_PROCESS_CPL	= 0,
	WAIT_PROCESS_WAITING	= 1,
	WAIT_PROCESS_ERR	= 2,
};

/**
 * struct hinic3_sge - 散列聚集项（SGE）
 * @hi_addr/lo_addr: 64 位地址的高/低 32 位
 * @len: 有效数据长度
 */
struct hinic3_sge {
	u32 hi_addr;
	u32 lo_addr;
	u32 len;
};

#ifdef static
#undef static
#define LLT_STATIC_DEF_SAVED
#endif

/* 将一段内存按 32bit 为单位转换为大端（长度需为 4B 的倍数） */
static inline void hinic3_cpu_to_be32(void *data, int len)
{
	int i, chunk_sz = sizeof(u32);
	int data_len = len;
	u32 *mem = data;

	if (!data)
		return;

	data_len = data_len / chunk_sz;

	for (i = 0; i < data_len; i++) {
		*mem = cpu_to_be32(*mem);
		mem++;
	}
}

/* 将一段内存按 32bit 为单位从大端转换为 CPU 端序 */
static inline void hinic3_be32_to_cpu(void *data, int len)
{
	int i, chunk_sz = sizeof(u32);
	int data_len = len;
	u32 *mem = data;

	if (!data)
		return;

	data_len = data_len / chunk_sz;

	for (i = 0; i < data_len; i++) {
		*mem = be32_to_cpu(*mem);
		mem++;
	}
}

/* 设置 SGE：写入 DMA 地址与长度（高/低 32 位拆分） */
static inline void hinic3_set_sge(struct hinic3_sge *sge, dma_addr_t addr,
				  int len)
{
	sge->hi_addr = upper_32_bits(addr);
	sge->lo_addr = lower_32_bits(addr);
	sge->len = len;
}

/*
 * 硬件端序转换占位宏/函数：某些平台编译期选择为 no-op，
 * 也可在特定 SoC/设备上替换为真正的字节序转换。
 */
#define hinic3_hw_be32(val) (val)
#define hinic3_hw_cpu32(val) (val)
#define hinic3_hw_cpu16(val) (val)

static inline void hinic3_hw_be32_len(void *data, int len)
{
}

static inline void hinic3_hw_cpu32_len(void *data, int len)
{
}

int hinic3_dma_zalloc_coherent_align(void *dev_hdl, u64 size, u64 align,
				     unsigned int flag,
				     struct hinic3_dma_addr_align *mem_align);

void hinic3_dma_free_coherent_align(void *dev_hdl,
				    struct hinic3_dma_addr_align *mem_align);

/* 轮询等待回调：返回值表征是否完成/错误/继续等待 */
typedef enum hinic3_wait_return (*wait_cpl_handler)(void *priv_data);

int hinic3_wait_for_timeout(void *priv_data, wait_cpl_handler handler,
			    u32 wait_total_ms, u32 wait_once_us);

#endif
